package xpn.platform.common.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.data.auditing.AuditableBeanWrapperFactory;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.core.event.ValidatingRepositoryEventListener;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer;
//import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;
import org.springframework.data.rest.webmvc.mapping.LinkCollector;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.Assert;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import xpn.platform.modules.sys.user.SysUserEventHandler;
import xpn.platform.modules.todo.todolink.TodoLinkEventHandler;
import xpn.platform.modules.workflow.definition.action.Action;
import xpn.platform.modules.workflow.definition.process.Process;
import xpn.platform.modules.workflow.definition.state.State;
import xpn.platform.modules.workflow.runtime.history.History;
import xpn.platform.modules.workflow.runtime.instance.Instance;
import xpn.platform.modules.workflow.runtime.todo.Todo;

import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

/**
 * 配置Spring Data Rest
 *
 * @author bobatkm
 * @version 2017年8月31日 下午12:38:20
 */
@Configuration
public class SpringDataRestConfigurer implements RepositoryRestConfigurer {

	/**
	 * RestTemplate，用于通过RESTful接口访问资源
	 * 
	 * @author bobatkm
	 * @version 2017年9月2日  下午9:27:40
	 * @param builder
	 * @return
	 */
	@Bean
	public RestTemplate restTemplate(RestTemplateBuilder builder) {
		return builder.build();
	}
	
	/**
	 * 创建校验Bean
	 * 
	 * @author bobatkm
	 * @version 2017年9月1日 下午11:47:35
	 * @return
	 */
	@Bean
	@Primary
	Validator validator() {
		return new LocalValidatorFactoryBean();
	}
	
	/**
	 * 监听Spring Data Rest自动创建的RESTful接口的创建和保存实体事件； 在保存和创建实体前执行校验；
	 * 首先是无法在dao层指定自动创建的RESTful接口是否校验，其次是可能会产生Transaction异常，导致无法捕获
	 */
	@Override
	public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {
		Validator validator = validator();
		validatingListener.addValidator("beforeCreate", validator);
		validatingListener.addValidator("afterCreate", validator);
		validatingListener.addValidator("beforeSave", validator);
	}


	/**
	 * 修改配置以返回 Id 字段
	 * @author zk
	 * @return
	 */
//	@Bean
//	public RepositoryRestConfigurer repositoryRestConfigurer() {
//		return new RepositoryRestConfigurerAdapter() {
//			@Override
//			public void configureRepositoryRestConfiguration(
//					RepositoryRestConfiguration config) {
//				config.exposeIdsFor(Process.class, State.class, Action.class, Instance.class, Todo.class, History.class);
//			}
//		};
//	}

	@Bean
	public SysUserEventHandler sysUserEventHandler() {
		return new SysUserEventHandler();
	}

	@Bean
	public TodoLinkEventHandler todoLinkEventHandler() {
		return new TodoLinkEventHandler();
	}
	
	/*@Bean
	public DraftEventHandler draftEventHandler() {
		return new DraftEventHandler();
	}

	@Bean
	public PurchasePlanEventHandler purchasePlanEventHandler() {
		return new PurchasePlanEventHandler();
	}*/

	static RepositoryRestConfigurer withConfig(Consumer<RepositoryRestConfiguration> consumer) {
		Assert.notNull(consumer, "Consumer must not be null!");
		return new RepositoryRestConfigurer() {
			public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors) {
				consumer.accept(config);
			}
		};
	}

	static RepositoryRestConfigurer withConfig(BiConsumer<RepositoryRestConfiguration, CorsRegistry> consumer) {
		Assert.notNull(consumer, "Consumer must not be null!");
		return new RepositoryRestConfigurer() {
			public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors) {
				consumer.accept(config, cors);
			}
		};
	}

	@Override
	public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors) {
	}

	@Override
	public void configureConversionService(ConfigurableConversionService conversionService) {
	}

	@Override
	public void configureExceptionHandlerExceptionResolver(ExceptionHandlerExceptionResolver exceptionResolver) {
	}

	@Override
	public void configureHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
	}

	@Override
	public void configureJacksonObjectMapper(ObjectMapper objectMapper) {
	}

	@Override
	public AuditableBeanWrapperFactory customizeAuditableBeanWrapperFactory(AuditableBeanWrapperFactory factory) {
		return factory;
	}

	@Override
	public LinkCollector customizeLinkCollector(LinkCollector collector) {
		return collector;
	}
	
}
